home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / uniq.zip / UNIQ.C < prev    next >
Text File  |  1994-07-10  |  8KB  |  335 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Case Larsen.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. char copyright[] =
  39. "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
  40.  All rights reserved.\n";
  41. #endif /* not lint */
  42.  
  43. #ifndef lint
  44. static char sccsid[] = "@(#)uniq.c    5.4 (Berkeley) 1/9/92";
  45. #endif /* not lint */
  46.  
  47. #include <errno.h>
  48. #include <stdio.h>
  49. #include <ctype.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #define index strchr
  53. #define rindex strrchr
  54.  
  55. int    opterr = 1,        /* if error message should be printed */
  56.     optind = 1,        /* index into parent argv vector */
  57.     optopt;            /* character checked for validity */
  58. char    *optarg;        /* argument associated with option */
  59.  
  60. #define    BADCH    (int)'?'
  61. #define    EMSG    ""
  62.  
  63. int
  64. getopt(int nargc, char * const *nargv, const char *ostr)
  65. {
  66.     static char *place = EMSG;        /* option letter processing */
  67.     register char *oli;            /* option letter list index */
  68.     char *p;
  69.  
  70.     if (!*place) {                /* update scanning pointer */
  71.         if (optind >= nargc || *(place = nargv[optind]) != '-') {
  72.             place = EMSG;
  73.             return(EOF);
  74.         }
  75.         if (place[1] && *++place == '-') {    /* found "--" */
  76.             ++optind;
  77.             place = EMSG;
  78.             return(EOF);
  79.         }
  80.     }                    /* option letter okay? */
  81.     if ((optopt = (int)*place++) == (int)':' ||
  82.         (oli = index(ostr, optopt)) == 0) {
  83.         /*
  84.          * if the user didn't specify '-' as an option,
  85.          * assume it means EOF.
  86.          */
  87.         if (optopt == (int)'-')
  88.             return(EOF);
  89.         if (!*place)
  90.             ++optind;
  91.         if (opterr) {
  92.             if ((p = rindex(*nargv, '/')) == 0)
  93.                 p = *nargv;
  94.             else
  95.                 ++p;
  96.             (void)fprintf(stderr, "%s: illegal option -- %c\n",
  97.                 p, optopt);
  98.         }
  99.         return(BADCH);
  100.     }
  101.     if (*++oli != ':') {            /* don't need argument */
  102.         optarg = NULL;
  103.         if (!*place)
  104.             ++optind;
  105.     }
  106.     else {                    /* need an argument */
  107.         if (*place)            /* no white space */
  108.             optarg = place;
  109.         else if (nargc <= ++optind) {    /* no arg */
  110.             place = EMSG;
  111.             if ((p = rindex(*nargv, '/')) == 0)
  112.                 p = *nargv;
  113.             else
  114.                 ++p;
  115.             if (opterr)
  116.                 (void)fprintf(stderr,
  117.                     "%s: option requires an argument -- %c\n",
  118.                     p, optopt);
  119.             return(BADCH);
  120.         }
  121.          else                /* white space */
  122.             optarg = nargv[optind];
  123.         place = EMSG;
  124.         ++optind;
  125.     }
  126.     return(optopt);                /* dump back option letter */
  127. }
  128.  
  129. #define    MAXLINELEN    (8 * 1024)
  130.  
  131. int cflag, dflag, uflag;
  132. int numchars, numfields, repeats;
  133. #define    __P(x) x
  134.  
  135. void     err __P((const char *, ...));
  136. FILE    *file __P((char *, char *));
  137. void     show __P((FILE *, char *));
  138. char    *skip __P((char *));
  139. void     obsolete __P((char *[]));
  140. void     usage __P((void));
  141.  
  142. int
  143. main (argc, argv)
  144.     int argc;
  145.     char *argv[];
  146. {
  147.     register char *t1, *t2;
  148.     FILE *ifp, *ofp;
  149.     int ch;
  150.     char *prevline, *thisline, *p;
  151.  
  152.     obsolete(argv);
  153.     while ((ch = getopt(argc, argv, "-cdf:s:u")) != EOF)
  154.         switch (ch) {
  155.         case '-':
  156.             --optind;
  157.             goto done;
  158.         case 'c':
  159.             cflag = 1;
  160.             break;
  161.         case 'd':
  162.             dflag = 1;
  163.             break;
  164.         case 'f':
  165.             numfields = strtol(optarg, &p, 10);
  166.             if (numfields < 0 || *p)
  167.                 err("illegal field skip value: %s", optarg);
  168.             break;
  169.         case 's':
  170.             numchars = strtol(optarg, &p, 10);
  171.             if (numchars < 0 || *p)
  172.                 err("illegal character skip value: %s", optarg);
  173.             break;
  174.         case 'u':
  175.             uflag = 1;
  176.             break;
  177.         case '?':
  178.         default:
  179.             usage();
  180.     }
  181.  
  182. done:    argc -= optind;
  183.     argv +=optind;
  184.  
  185.     /* If no flags are set, default is -d -u. */
  186.     if (cflag) {
  187.         if (dflag || uflag)
  188.             usage();
  189.     } else if (!dflag && !uflag)
  190.         dflag = uflag = 1;
  191.  
  192.     switch(argc) {
  193.     case 0:
  194.         ifp = stdin;
  195.         ofp = stdout;
  196.         break;
  197.     case 1:
  198.         ifp = file(argv[0], "r");
  199.         ofp = stdout;
  200.         break;
  201.     case 2:
  202.         ifp = file(argv[0], "r");
  203.         ofp = file(argv[1], "w");
  204.         break;
  205.     default:
  206.         usage();
  207.     }
  208.  
  209.     prevline = malloc(MAXLINELEN);
  210.     thisline = malloc(MAXLINELEN);
  211.     (void)fgets(prevline, MAXLINELEN, ifp);
  212.  
  213.     while (fgets(thisline, MAXLINELEN, ifp)) {
  214.         /* If requested get the chosen fields + character offsets. */
  215.         if (numfields || numchars) {
  216.             t1 = skip(thisline);
  217.             t2 = skip(prevline);
  218.         } else {
  219.             t1 = thisline;
  220.             t2 = prevline;
  221.         }
  222.  
  223.         /* If different, print; set previous to new value. */
  224.         if (strcmp(t1, t2)) {
  225.             show(ofp, prevline);
  226.             t1 = prevline;
  227.             prevline = thisline;
  228.             thisline = t1;
  229.             repeats = 0;
  230.         } else
  231.             ++repeats;
  232.     }
  233.     show(ofp, prevline);
  234.     exit(0);
  235.     return 1;
  236. }
  237.  
  238. /*
  239.  * show --
  240.  *    Output a line depending on the flags and number of repetitions
  241.  *    of the line.
  242.  */
  243. void
  244. show(ofp, str)
  245.     FILE *ofp;
  246.     char *str;
  247. {
  248.     if (cflag)
  249.         (void)fprintf(ofp, "%4d %s", repeats + 1, str);
  250.     if (dflag && repeats || uflag && !repeats)
  251.         (void)fprintf(ofp, "%s", str);
  252. }
  253.  
  254. char *
  255. skip(str)
  256.     register char *str;
  257. {
  258.     register int infield, nchars, nfields;
  259.  
  260.     for (nfields = numfields, infield = 0; nfields && *str; ++str)
  261.         if (isspace(*str)) {
  262.             if (infield) {
  263.                 infield = 0;
  264.                 --nfields;
  265.             }
  266.         } else if (!infield)
  267.             infield = 1;
  268.     for (nchars = numchars; nchars-- && *str; ++str);
  269.     return(str);
  270. }
  271.  
  272. FILE *
  273. file(name, mode)
  274.     char *name, *mode;
  275. {
  276.     FILE *fp;
  277.  
  278.     if ((fp = fopen(name, mode)) == NULL)
  279.         err("%s: %s", name, strerror(errno));
  280.     return(fp);
  281. }
  282.  
  283. void
  284. obsolete(argv)
  285.     char *argv[];
  286. {
  287.     int len;
  288.     char *ap, *p, *start;
  289.  
  290.     while ((ap = *++argv) != 0) {
  291.         /* Return if "--" or not an option of any form. */
  292.         if (ap[0] != '-') {
  293.             if (ap[0] != '+')
  294.                 return;
  295.         } else if (ap[1] == '-')
  296.             return;
  297.         if (!isdigit(ap[1]))
  298.             continue;
  299.         /*
  300.          * Digit signifies an old-style option.  Malloc space for dash,
  301.          * new option and argument.
  302.          */
  303.         len = strlen(ap);
  304.         if ((start = p = malloc(len + 3)) == NULL)
  305.             err("%s", strerror(errno));
  306.         *p++ = '-';
  307.         *p++ = ap[0] == '+' ? 's' : 'f';
  308.         (void)strcpy(p, ap + 1);
  309.         *argv = start;
  310.     }
  311. }
  312.  
  313. void
  314. usage()
  315. {
  316.     (void)fprintf(stderr,
  317.         "usage: uniq [-c | -du] [-f fields] [-s chars] [input [output]]\n");
  318.     exit(1);
  319. }
  320.  
  321. #include <stdarg.h>
  322.  
  323. void
  324. err(const char *fmt, ...)
  325. {
  326.     va_list ap;
  327.     va_start(ap, fmt);
  328.     (void)fprintf(stderr, "uniq: ");
  329.     (void)vfprintf(stderr, fmt, ap);
  330.     va_end(ap);
  331.     (void)fprintf(stderr, "\n");
  332.     exit(1);
  333.     /* NOTREACHED */
  334. }
  335.